﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using QuantitativeInvestment.Bean;
using QuantitativeInvestment.Tools;
namespace QuantitativeInvestment.Model
{
    class TurnOverModel:Model
    {
        public TurnOverModel()
        {
            this.name = "换手率模型";
            Parameter p = new Parameter("观察时间", 30);
            this.paraList.Add(p.name, p);

            p = new Parameter("持有时间", 30);
            this.paraList.Add(p.name, p);

            p = new Parameter("排序", "低");
            p.type = "enum";
            p.enumList.Add("低");
            p.enumList.Add("高");
            this.paraList.Add(p.name, p);

            p = new Parameter("比较方法", "绝对");
            p.type = "enum";
            p.enumList.Add("绝对");
            p.enumList.Add("缩量");
            this.paraList.Add(p.name, p);

            p = new Parameter("缩量范围", "50");
            this.paraList.Add(p.name, p);

            p = new Parameter("是否比例", "是");
            p.type = "enum";
            p.enumList.Add("是");
            p.enumList.Add("否");
            this.paraList.Add(p.name, p);

            p = new Parameter("范围开始", 0);
            this.paraList.Add(p.name, p);

            p = new Parameter("范围结束", 30);
            this.paraList.Add(p.name, p);

            this.factorList.Add(Factor.Factor.createFactorByName("换手率"));
        }

        public override List<TradingStock> buy(List<TradingStock> stockList, string tradingDate)
        {

            MathLib mathLib = new MathLib();
            List<TradingStock> selectedStocks = new List<TradingStock>();

            int observePeriod = Int32.Parse(this.paraList["观察时间"].value.ToString());
            string compareType = this.paraList["比较方法"].value.ToString();
            int currentPosition = this.container.tradingDates.IndexOf(tradingDate);
            string startDate;

            //如果超过时间范围就不返回数值
            if (currentPosition - observePeriod < 0)
                return selectedStocks;
            else
                startDate = this.container.tradingDates[currentPosition - observePeriod];

            List<TradingStock> comparedStocks = new List<TradingStock>();
            foreach (TradingStock tradingStock in stockList)
            {
                Stock currentStock = this.container.stocks[tradingStock.code];

                int initialStartPosition = currentStock.tradingDateList.IndexOf(currentStock.startDate);

                int stockStartPosition = currentStock.tradingDateList.IndexOf(startDate);

                int stockCurrentPosition = currentStock.tradingDateList.IndexOf(tradingDate);

                //如果之前没有数据，则跳过该个股，不作为选择
                if (stockStartPosition == -1 || stockCurrentPosition == -1)
                {
                    continue;
                }

                double[] turnOvers = this.container.stocks[tradingStock.code].factors["换手率"];
                if (compareType == "绝对")
                {
                    double[] selectedTurnOvers = new double[stockCurrentPosition - stockStartPosition];
                    Array.Copy(turnOvers, stockStartPosition - initialStartPosition, selectedTurnOvers, 0, selectedTurnOvers.Length);
                    tradingStock.comparedValue = selectedTurnOvers.Average();
                }
                else if (compareType == "缩量")
                {
                    int compairedPeriod = Int32.Parse(this.paraList["缩量范围%"].value.ToString());
                    int lengthPeriod1 =( stockCurrentPosition - stockStartPosition )* compairedPeriod / 100;
                    int lengthPeriod2 = (stockCurrentPosition - stockStartPosition) - lengthPeriod1;
                    double[] period1TurnOvers = new double[lengthPeriod1];
                    double[] period2TurnOvers = new double[lengthPeriod2];
                    Array.Copy(turnOvers, stockStartPosition - initialStartPosition, period1TurnOvers, 0, period1TurnOvers.Length);
                    Array.Copy(turnOvers, stockStartPosition - initialStartPosition + lengthPeriod1, period2TurnOvers, 0, period2TurnOvers.Length);
                    tradingStock.comparedValue = period2TurnOvers.Average() / period1TurnOvers.Average();
                }
                tradingStock.buyDate = tradingDate;
                comparedStocks.Add(tradingStock);
            }
            if (comparedStocks.Count == 0)
                return selectedStocks;

            string sortType = this.paraList["排序"].value.ToString();

            comparedStocks = this.sort(comparedStocks, sortType);

            //开始选择
            string isPercent = this.paraList["是否比例"].value.ToString();
            int selectStartPosition = 0;
            int selectEndPosition = 0;
            if (isPercent == "是")
            {
                int startPercent = Int32.Parse(this.paraList["范围开始"].value.ToString());
                selectStartPosition = Convert.ToInt32(startPercent * 0.01 * comparedStocks.Count);

                int endPercent = Int32.Parse(this.paraList["范围结束"].value.ToString());
                selectEndPosition = Convert.ToInt32(endPercent * 0.01 * comparedStocks.Count);
            }
            else if (isPercent == "否")
            {
                selectStartPosition = Int32.Parse(this.paraList["范围开始"].value.ToString());
                selectEndPosition = Int32.Parse(this.paraList["范围结束"].value.ToString());
            }


            selectedStocks = comparedStocks.GetRange(selectStartPosition, selectEndPosition - selectStartPosition);

            return selectedStocks;
        }

        public override List<TradingStock> sell(List<TradingStock> stockList, string tradingDate)
        {
            int holdPeriod = Int32.Parse(this.paraList["持有时间"].value.ToString());
            int buyPosition = this.container.tradingDates.IndexOf(tradingDate);

            //如果超出我们设定的日期范围就返回空
            if (buyPosition + holdPeriod  >= this.container.tradingDates.Count)
                return new List<TradingStock>();
            string sellDate = this.container.tradingDates[buyPosition + holdPeriod];
            foreach (TradingStock tradingStock in stockList)
            {
                tradingStock.sellDate = sellDate;
            }
            return stockList;
        }
    }
}
